
#ifndef DXF_LIB_H
#define DXF_LIB_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __GCC2x__
#include <sstream>
#endif

#include "dxf_attributes.h"
#include "dxf_codes.h"
#include "dxf_entities.h"
#include "dxf_writer_ascii.h"
#include "dxflib_export.h"

#ifdef _WIN32
#undef M_PI
#define M_PI   3.14159265358979323846
#pragma warning(disable : 4800)
#endif

#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif

class DXF_CreationInterface;
class DXF_WriterA;


#define DL_VERSION     "0.0.0.1"

#define DL_UNKNOWN               0
#define DL_LAYER                10
#define DL_BLOCK                11
#define DL_ENDBLK               12
#define DL_LINETYPE             13
#define DL_SETTING              50
#define DL_ENTITY_POINT        100
#define DL_ENTITY_LINE         101
#define DL_ENTITY_POLYLINE     102
#define DL_ENTITY_LWPOLYLINE   103
#define DL_ENTITY_VERTEX       104
#define DL_ENTITY_SPLINE       105
#define DL_ENTITY_KNOT         106
#define DL_ENTITY_CONTROLPOINT 107
#define DL_ENTITY_ARC          108
#define DL_ENTITY_CIRCLE       109
#define DL_ENTITY_ELLIPSE      110
#define DL_ENTITY_INSERT       111
#define DL_ENTITY_TEXT         112
#define DL_ENTITY_MTEXT        113
#define DL_ENTITY_DIMENSION    114
#define DL_ENTITY_LEADER       115
#define DL_ENTITY_HATCH        116
#define DL_ENTITY_ATTRIB       117
#define DL_ENTITY_IMAGE        118
#define DL_ENTITY_IMAGEDEF     119
#define DL_ENTITY_TRACE        120
#define DL_ENTITY_SOLID        121
#define DL_ENTITY_3DFACE       122
#define DL_ENTITY_SEQEND       123


/**
 * Reading and writing of DXF files.
 *
 * This class can read in a DXF file and calls methods from the 
 * interface DL_EntityContainer to add the entities to the
 * contianer provided by the user of the library.
 *
 * It can also be used to write DXF files to a certain extent.
 *
 * When saving entities, special values for colors and linetypes 
 * can be used:
 *
 * Special colors are 0 (=BYBLOCK) and 256 (=BYLAYER).
 * Special linetypes are "BYLAYER" and "BYBLOCK".
 */
class DXFLIB_EXPORT DXF_Lib {
public:
    DXF_Lib();
    ~DXF_Lib();

    bool in(const string& file,
            DXF_CreationInterface* creationInterface);
    bool readDxfGroups(FILE* fp,
                       DXF_CreationInterface* creationInterface,
					   int* errorCounter = NULL);
    static bool getChoppedLine(char* s, unsigned int size,
                               FILE *stream);
    
#ifndef __GCC2x__
    bool readDxfGroups(std::stringstream &stream,
                       DXF_CreationInterface* creationInterface,
					   int* errorCounter = NULL);
    bool in(std::stringstream &stream,
            DXF_CreationInterface* creationInterface);
    static bool getChoppedLine(char *s, unsigned int size,
                               std::stringstream &stream);
#endif

    static bool stripWhiteSpace(char** s);

    bool processDXFGroup(DXF_CreationInterface* creationInterface,
                         int groupCode, const char* groupValue);
    void addSetting(DXF_CreationInterface* creationInterface);
    void addLayer(DXF_CreationInterface* creationInterface);
    void addBlock(DXF_CreationInterface* creationInterface);
    void endBlock(DXF_CreationInterface* creationInterface);

    void addPoint(DXF_CreationInterface* creationInterface);
    void addLine(DXF_CreationInterface* creationInterface);
	
    void addPolyline(DXF_CreationInterface* creationInterface);
    void addVertex(DXF_CreationInterface* creationInterface);
	
    void addSpline(DXF_CreationInterface* creationInterface);
    //void addKnot(DL_CreationInterface* creationInterface);
    //void addControlPoint(DL_CreationInterface* creationInterface);
	
    void addArc(DXF_CreationInterface* creationInterface);
    void addCircle(DXF_CreationInterface* creationInterface);
    void addEllipse(DXF_CreationInterface* creationInterface);
    void addInsert(DXF_CreationInterface* creationInterface);
    
    void addTrace(DXF_CreationInterface* creationInterface);
    void add3dFace(DXF_CreationInterface* creationInterface);
    void addSolid(DXF_CreationInterface* creationInterface);

    void addMText(DXF_CreationInterface* creationInterface);
	bool handleMTextData(DXF_CreationInterface* creationInterface);
	bool handleLWPolylineData(DXF_CreationInterface* creationInterface);
	bool handleSplineData(DXF_CreationInterface* creationInterface);
	bool handleLeaderData(DXF_CreationInterface* creationInterface);
	bool handleHatchData(DXF_CreationInterface* creationInterface);
	
    void addText(DXF_CreationInterface* creationInterface);
    void addAttrib(DXF_CreationInterface* creationInterface);
    DXF_DimensionAttribute getDimData();
    void addDimLinear(DXF_CreationInterface* creationInterface);
    void addDimAligned(DXF_CreationInterface* creationInterface);
    void addDimRadial(DXF_CreationInterface* creationInterface);
    void addDimDiametric(DXF_CreationInterface* creationInterface);
    void addDimAngular(DXF_CreationInterface* creationInterface);
    void addDimAngular3P(DXF_CreationInterface* creationInterface);
    void addDimOrdinate(DXF_CreationInterface* creationInterface);
    void addLeader(DXF_CreationInterface* creationInterface);
    void addHatch(DXF_CreationInterface* creationInterface);
    void addImage(DXF_CreationInterface* creationInterface);
    void addImageDef(DXF_CreationInterface* creationInterface);
    
    void addComment(DXF_CreationInterface* creationInterface, const char* comment);

	void endEntity(DXF_CreationInterface* creationInterface);
	
    void endSequence(DXF_CreationInterface* creationInterface);
	
	int  stringToInt(const char* s, bool* ok=NULL);	

    DXF_WriterA* out(const char* file,
                    DXF_Codes::version version=VER_2000);

    void writeHeader(DXF_WriterA& dw);

    void writePoint(DXF_WriterA& dw,
                    const DXF_PointAttribute& data,
                    const DXF_Attributes& attrib);
    void writeLine(DXF_WriterA& dw,
                   const DXF_LineAttribute& data,
                   const DXF_Attributes& attrib);
    void writePolyline(DXF_WriterA& dw,
                       const DXF_PolylineAttribute& data,
                       const DXF_Attributes& attrib);
    void writeVertex(DXF_WriterA& dw,
                     const DXF_VertexAttribute& data);
    void writePolylineEnd(DXF_WriterA& dw);
    void writeSpline(DXF_WriterA& dw,
                       const DXF_SplineAttribute& data,
                       const DXF_Attributes& attrib);
    void writeControlPoint(DXF_WriterA& dw,
                     const DXF_ControlPointAttribute& data);
    void writeKnot(DXF_WriterA& dw,
                     const DXF_KnotAttribute& data);
    void writeCircle(DXF_WriterA& dw,
                     const DXF_CircleAttribute& data,
                     const DXF_Attributes& attrib);
    void writeArc(DXF_WriterA& dw,
                  const DXF_ArcAttribute& data,
                  const DXF_Attributes& attrib);
    void writeEllipse(DXF_WriterA& dw,
                      const DXF_EllipseAttribute& data,
                      const DXF_Attributes& attrib);
    void writeSolid(DXF_WriterA& dw,
                   const DXF_SolidAttribute& data,
                   const DXF_Attributes& attrib);
    void write3dFace(DXF_WriterA& dw,
                   const DXF_3dFaceAttribute& data,
                   const DXF_Attributes& attrib);
    void writeInsert(DXF_WriterA& dw,
                     const DXF_InsertAttribute& data,
                     const DXF_Attributes& attrib);
    void writeMText(DXF_WriterA& dw,
                    const DXF_MTextAttribute& data,
                    const DXF_Attributes& attrib);
    void writeText(DXF_WriterA& dw,
                    const DXF_TextAttribute& data,
                    const DXF_Attributes& attrib);
    void writeDimAligned(DXF_WriterA& dw,
                         const DXF_DimensionAttribute& data,
                         const DXF_DimAlignedAttribute& edata,
                         const DXF_Attributes& attrib);
    void writeDimLinear(DXF_WriterA& dw,
                        const DXF_DimensionAttribute& data,
                        const DXF_DimLinearAttribute& edata,
                        const DXF_Attributes& attrib);
    void writeDimRadial(DXF_WriterA& dw,
                        const DXF_DimensionAttribute& data,
                        const DXF_DimRadialAttribute& edata,
                        const DXF_Attributes& attrib);
    void writeDimDiametric(DXF_WriterA& dw,
                           const DXF_DimensionAttribute& data,
                           const DXF_DimDiametricAttribute& edata,
                           const DXF_Attributes& attrib);
    void writeDimAngular(DXF_WriterA& dw,
                         const DXF_DimensionAttribute& data,
                         const DXF_DimAngularAttribute& edata,
                         const DXF_Attributes& attrib);
    void writeDimAngular3P(DXF_WriterA& dw,
                           const DXF_DimensionAttribute& data,
                           const DXF_DimAngular3PAttribute& edata,
                           const DXF_Attributes& attrib);
    void writeDimOrdinate(DXF_WriterA& dw,
                         const DXF_DimensionAttribute& data,
                         const DXF_DimOrdinateAttribute& edata,
                         const DXF_Attributes& attrib);
    void writeLeader(DXF_WriterA& dw,
                     const DXF_LeaderAttribute& data,
                     const DXF_Attributes& attrib);
    void writeLeaderVertex(DXF_WriterA& dw,
                           const DXF_LeaderVertexAttribute& data);
    void writeHatch1(DXF_WriterA& dw,
                     const DXF_HatchAttribute& data,
                     const DXF_Attributes& attrib);
    void writeHatch2(DXF_WriterA& dw,
                     const DXF_HatchAttribute& data,
                     const DXF_Attributes& attrib);
    void writeHatchLoop1(DXF_WriterA& dw,
                         const DXF_HatchLoopAttribute& data);
    void writeHatchLoop2(DXF_WriterA& dw,
                         const DXF_HatchLoopAttribute& data);
    void writeHatchEdge(DXF_WriterA& dw,
                        const DXF_HatchEdgeAttribute& data);

    int writeImage(DXF_WriterA& dw,
                   const DXF_ImageAttribute& data,
                   const DXF_Attributes& attrib);

    void writeImageDef(DXF_WriterA& dw, int handle,
                       const DXF_ImageAttribute& data);

    void writeLayer(DXF_WriterA& dw,
                    const DXF_LayerAttribute& data,
                    const DXF_Attributes& attrib);

    void writeLineType(DXF_WriterA& dw,
                       const DXF_LineTypeAttribute& data);

    void writeAppid(DXF_WriterA& dw, const string& name);

    void writeBlock(DXF_WriterA& dw,
                    const DXF_BlockAttribute& data);
    void writeEndBlock(DXF_WriterA& dw, const string& name);

    void writeVPort(DXF_WriterA& dw);
    void writeStyle(DXF_WriterA& dw);
    void writeView(DXF_WriterA& dw);
    void writeUcs(DXF_WriterA& dw);
    void writeDimStyle(DXF_WriterA& dw, 
	                   double dimasz, double dimexe, double dimexo,
					   double dimgap, double dimtxt);
    void writeBlockRecord(DXF_WriterA& dw);
    void writeBlockRecord(DXF_WriterA& dw, const string& name);
    void writeObjects(DXF_WriterA& dw);
    void writeObjectsEnd(DXF_WriterA& dw);
    
    void writeComment(DXF_WriterA& dw, const string& comment);

    /**
     * Converts the given string into a double or returns the given 
     * default valud (def) if value is NULL or empty.
     */
    static double toReal(const char* value, double def=0.0) {
       if (value!=NULL && value[0] != '\0') {
            double ret;
            if (strchr(value, ',') != NULL) {
               char* tmp = new char[strlen(value)+1];
               strcpy(tmp, value);
               DXF_WriterA::strReplace(tmp, ',', '.');
               ret = atof(tmp);
      		   delete[] tmp;
            }
            else {
               ret = atof(value);
            }
			return ret;
        } else {
            return def;
        }
    }
    /**
     * Converts the given string into an int or returns the given 
     * default valud (def) if value is NULL or empty.
     */
    static int toInt(const char* value, int def=0) {
        if (value!=NULL && value[0] != '\0') {
            return atoi(value);
        } else {
            return def;
        }
    }
    /**
     * Converts the given string into a string or returns the given 
     * default valud (def) if value is NULL or empty.
     */
    static const char* toString(const char* value, const char* def="") {
        if (value!=NULL && value[0] != '\0') {
            return value;
        } else {
            return def;
        }
    }

	static bool checkVariable(const char* var, DXF_Codes::version version);

	DXF_Codes::version getVersion() {
		return version;
	}

	int getLibVersion(const char* str);

	static void test();

private:
    DXF_Codes::version version;
    unsigned long styleHandleStd;

	string polylineLayer;
    double* vertices;
    int maxVertices;
    int vertexIndex;
	
    double* knots;
    int maxKnots;
    int knotIndex;
	
    double* controlPoints;
    int maxControlPoints;
    int controlPointIndex;

    double* leaderVertices;
    int maxLeaderVertices;
    int leaderVertexIndex;

    // array of hatch loops
    DXF_HatchLoopAttribute* hatchLoops;
    int maxHatchLoops;
    int hatchLoopIndex;
    // array in format [loop#][edge#]
    DXF_HatchEdgeAttribute** hatchEdges;
    int* maxHatchEdges;
    int* hatchEdgeIndex;
    bool dropEdges;

    // Bulge for the next vertex.
    double bulge;

    // Only the useful part of the group code
    char groupCodeTmp[DL_DXF_MAXLINE+1];
    // ...same as integer
    unsigned int groupCode;
    // Only the useful part of the group value
    char groupValue[DL_DXF_MAXLINE+1];
    // Current entity type
    int currentEntity;
    // Value of the current setting
    char settingValue[DL_DXF_MAXLINE+1];
    // Key of the current setting (e.g. "$ACADVER")
    char settingKey[DL_DXF_MAXLINE+1];
    // Stores the group codes
    char values[DL_DXF_MAXGROUPCODE][DL_DXF_MAXLINE+1];
    // First call of this method. We initialize all group values in
    //  the first call.
    bool firstCall;
    // Attributes of the current entity (layer, color, width, line type)
    DXF_Attributes attrib;
	// library version. hex: 0x20003001 = 2.0.3.1
	int libVersion;
};

#endif

// EOF
